#include "stdafx.h"
#include "ui_slider.h"

_SSL_BEGIN
_SSUIL_BEGIN

UISlider::UISlider()
{
	focus_sensitive_ = false;
	background_transparent_ = true;
	properties_ |= kControlPropertyAcceptMouseWheel;

	//
	slider_type_ = kSTypeHorz;
	// thumb_
	min_value_ = 0;
	max_value_ = 0;
	value_ = 0;
	change_value_click_outof_thumb_ = 1;
	page_step_value_ = 30;
	line_step_value_ = 10;
	draging_ = false;
	// drag_mouse_pt_
	// drag_thmub_pt_
	ud_convert_ = false;
}

UISlider::~UISlider()
{

}

bool UISlider::ApplyAttributes(IUIBuilderInterface *ui_builder, 
	IUIXMLDocumentInterface *xml_document, UIXmlNode node)
{
	if(!__super::ApplyAttributes(ui_builder, xml_document, node))
		return false;

	UIXmlAttribute attribute = NULL;

	attribute = xml_document->FirstAttribute(node, "slider_type");
	if(attribute != NULL)
	{
		UISliderType type = kSTypeNone;
		if(strstr(xml_document->AttributeValue(attribute), "horizontal") != NULL)
			type = kSTypeHorz;
		else if(strstr(xml_document->AttributeValue(attribute), "vertical") != NULL)
			type = kSTypeVert;
		if(type != kSTypeNone)
			SetSliderType(type);
	}

	attribute = xml_document->FirstAttribute(node, "range");
	if(attribute != NULL)
	{
		int min_v = 0, max_v = 0;
		if(UIValueParseUtil::ParseIntInt(xml_document->AttributeValue(attribute), min_v, max_v) == 2)
			SetRange(min_v, max_v);
	}

	attribute = xml_document->FirstAttribute(node, "value");
	if(attribute != NULL)
	{
		int n = 0;
		if(UIValueParseUtil::ParseInt(xml_document->AttributeValue(attribute), n) == 1)
			SetValue(n);
	}

	attribute = xml_document->FirstAttribute(node, "change_value_of_click_outof_thumb");
	if(attribute != NULL)
	{
		int n = 0;
		if(UIValueParseUtil::ParseInt(xml_document->AttributeValue(attribute), n) == 1)
			SetChangeValueOfClickOutofThumb(n);
	}

	attribute = xml_document->FirstAttribute(node, "up_down_convert");
	if(attribute != NULL)
	{
		bool f = false;
		if(UIValueParseUtil::ParseBool(xml_document->AttributeValue(attribute), f) == 1)
		{
			SetUpDownConvertMode(f);
		}
	}

	return true;
}

void UISlider::AfterBuild(IUIBuilderInterface *ui_builder,
	IUIXMLDocumentInterface *xml_document, UIXmlNode node)
{
	__super::AfterBuild(ui_builder, xml_document, node);

	UIXmlAttribute attribute = NULL;
	attribute = xml_document->FirstAttribute(node, "thumb_button_name");
	if(attribute != NULL)
	{
		scoped_ref_ptr<IUIControlInterface> thumb_base = FindControl(
			auto_cvt(xml_document->AttributeValue(attribute)).c_tstr());
		if(thumb_base != NULL)
		{
			SetThumbControlOnChilds(thumb_base);
		}
	}
}

void UISlider::OnRecalcChildsLayoutOnSizeChange()
{
	if(draging_ || thumb_.get() == NULL)
	{
		__super::OnRecalcChildsLayoutOnSizeChange();
		return;
	}

	int tleft = 0, ttop = 0;
	if(!GetThumbLeftTop(tleft, ttop))
		return;

	UIPresetPosition pp = thumb_->GetPresetPosition();
	UIPresetPosition pp_old = pp;
	if(slider_type_ == kSTypeHorz)
	{
		pp.SetLeft(tleft, ud_convert_ ? false : true);
	}else if(slider_type_ == kSTypeVert)
	{
		pp.SetTop(ttop, ud_convert_ ? false : true);
	}

	bool old_align = false;
	bool align = false;
	if(pp_old.GetLeft(&old_align) != pp.GetLeft(&align) || old_align != align
		|| pp_old.GetTop(&old_align) != pp.GetTop(&align) || old_align != align)
	{
		thumb_->SetPresetPosition(pp);
	}
}

void UISlider::DoEvent(UIEvent &evt)
{
	scoped_ref_ptr<IUIManagerInterface> win_man = GetWindowManager();
	if(win_man == NULL)
		return;

	if(evt.type == kEvtLButtonDown && thumb_ != NULL)
	{
		UIRect my_client = GetVisibleClientPositionOnClient();
		UIRect thumb_pos = thumb_->GetVisiblePositionOnClient();

		int value_incre = 0;
		if(slider_type_ == kSTypeHorz)
		{
			if(evt.mouse_point.x >= my_client.left
				&& evt.mouse_point.x < thumb_pos.left)
			{
				value_incre = -change_value_click_outof_thumb_;
			}else if(evt.mouse_point.x > thumb_pos.right
				&& evt.mouse_point.x < my_client.right)
			{
				value_incre = change_value_click_outof_thumb_;
			}
		}else if(slider_type_ == kSTypeVert)
		{
			if(evt.mouse_point.y >= my_client.top
				&& evt.mouse_point.y < thumb_pos.top)
			{
				value_incre = -change_value_click_outof_thumb_;
			}else if(evt.mouse_point.y > thumb_pos.bottom
				&& evt.mouse_point.y < my_client.bottom)
			{
				value_incre = change_value_click_outof_thumb_;
			}
		}
		if(value_incre != 0)
		{
			if(ud_convert_)
				value_incre *= -1;
			SetValue(GetValue() + value_incre);
		}
	}else if(evt.type == kEvtMouseWheel)
	{
		SendNotify(UINotify(_T("mousewheel"), this, evt.wparam,
			(__int64)evt.key_state));
	}
	__super::DoEvent(evt);
}

void UISlider::SetSliderType(UISliderType tp)
{
	if(slider_type_ == tp)
		return;
	slider_type_ = tp;
	SmartSetNeedUpdate(true);

	SendNotify(UINotify(_T("slider_type_changed")
		, this, MAKEINT64(0, slider_type_)));
}

bool UISlider::SetRange(int min_v, int max_v)
{
	if(min_v > max_v)
		return false;
	if(min_v == min_value_ && max_v == max_value_)
		return true;
	min_value_ = min_v;
	max_value_ = max_v;

	SetNeedUpdate(true);

	SendNotify(UINotify(_T("slider_range_changed")
		, this, MAKEINT64(max_value_, min_value_)));

	return true;
}

bool UISlider::SetValue(int v)
{
	if(v < min_value_)
	{
		v = min_value_;
		if(v == value_)
			return false;
	}
	if(v > max_value_)
	{
		v = max_value_;
		if(v == value_)
			return false;
	}
	if(v == value_)
		return true;
	value_ = v;

	SetNeedUpdate(true);

	OnValueChanged(static_cast<IUIControlInterface*>(this));

	SendNotify(
		UINotify(_T("slider_value_changed"), this, MAKEINT64(0, value_))
		);

	return true;
}

void UISlider::GetRange(int &min_v, int &max_v) const
{
	min_v = min_value_;
	max_v = max_value_;
}

int UISlider::GetValue() const
{
	return value_;
}

void UISlider::SetChangeValueOfClickOutofThumb(int v)
{
	change_value_click_outof_thumb_  = v;
	if(change_value_click_outof_thumb_ < 0)
		change_value_click_outof_thumb_ = -change_value_click_outof_thumb_;
}

void UISlider::SetUpDownConvertMode(bool f)
{
	ud_convert_ = f;
	SetNeedUpdate(true);

	SendNotify(
		UINotify(_T("slider_ud_convert_mode_changed"), this, MAKEINT64(0, value_))
		);
}

bool UISlider::ScrollHome()
{
	return SetValue(ud_convert_ ? max_value_ : min_value_);
}

bool UISlider::ScrollEnd()
{
	return SetValue(ud_convert_ ? min_value_ : max_value_);
}

bool UISlider::ScrollPageUp()
{
	return SetValue(value_ 
		+ (ud_convert_ ? page_step_value_ : -page_step_value_));
}

bool UISlider::ScrollPageDown()
{
	return SetValue(value_
		+ (ud_convert_ ? -page_step_value_ : page_step_value_));
}

bool UISlider::ScrollLineUp()
{
	return SetValue(value_
		+ (ud_convert_ ? line_step_value_ : -line_step_value_));
}

bool UISlider::ScrollLineDown()
{
	return SetValue(value_
		+ (ud_convert_ ? -line_step_value_ : line_step_value_));
}

bool UISlider::ScrollByKey(tchar ch)
{
	switch(ch)
	{
	case VK_HOME:
		return ScrollHome();
	case VK_END:
		return ScrollEnd();
	case VK_PRIOR:
		return ScrollPageUp();
	case VK_NEXT:
		return ScrollPageDown();
	case VK_LEFT:
	case VK_UP:
		return ScrollLineUp();
	case VK_RIGHT:
	case VK_DOWN:
		return ScrollLineDown();
	default:
		break;
	}
	return false;
}

bool UISlider::SetThumbControlOnChilds(IUIControlInterface *thumb)
{
	if(thumb_ != NULL)
	{
		if(!IsControlExists(thumb))
			return false;
	}

	if(thumb_ != NULL)
		thumb_->OnEvent -= make_delegate(this, &UISlider::DelegteOnThumbEvent);
	if(thumb != NULL)
		thumb_ = thumb->as_weak_ptr();
	if(thumb_ != NULL)
		thumb_->OnEvent += make_delegate(this, &UISlider::DelegteOnThumbEvent);
	if(thumb_ != NULL)
	{
		UIFocusableControl *focusable_control = 
			dynamic_cast<UIFocusableControl*>(thumb_.get());
		if(focusable_control != NULL)
			focusable_control->SetFocusSensitive(false);
	}
	return true;
}

double UISlider::UnitLength()
{
	if(thumb_ == NULL)
		return 0;

	UIRect my_rt = GetClientPositionOnClient();

	int me_len = 0, thumb_len = 0;
	if(slider_type_ == kSTypeHorz)
	{
		me_len = my_rt.Width();
		thumb_len = thumb_->GetPosition().Width();
	}else if(slider_type_ == kSTypeVert)
	{
		me_len = my_rt.Height();
		thumb_len = thumb_->GetPosition().Height();
	}

	double unit_len = (double)(me_len - thumb_len) / ((double)(max_value_ - min_value_));
	if(unit_len < 0)
		unit_len = 0;
	return unit_len;
}

bool UISlider::GetThumbLeftTop(int &left, int &top)
{
	if(thumb_ == NULL)
		return false;

	double uni_len = UnitLength();
	if(uni_len == 0)
		return false;

	left = 0;
	top = 0;

	if(slider_type_ == kSTypeHorz)
	{
		left += (int)((value_ - min_value_) * uni_len);
	}else if(slider_type_ == kSTypeVert)
	{
		top += (int)((value_ - min_value_) * uni_len);
	}

	return true;
}

bool UISlider::GetThumbLeftTopOnDrag(int &left, int &top, UIPoint &mouse)
{
	if(thumb_ == NULL)
		return false;

	double uni_len = UnitLength();
	if(uni_len == 0)
		return false;

	left = drag_thmub_pt_.x;
	top = drag_thmub_pt_.y;

	int offset = 0;
	UISize my_rt = GetClientSize();
	if(slider_type_ == kSTypeHorz)
	{
		left = drag_thmub_pt_.x + (ud_convert_ ? -1 : 1) * (mouse.x - drag_mouse_pt_.x);
		if(left < 0)
			left = 0;
		else if(left > my_rt.cx - thumb_->GetPosition().Width())
			left = my_rt.cx - thumb_->GetPosition().Width();
		offset = left;
	}else if(slider_type_ == kSTypeVert)
	{
		top = drag_thmub_pt_.y + (ud_convert_ ? -1 : 1) * (mouse.y - drag_mouse_pt_.y);
		int raw_top = top;
		if(top < 0)
			top = 0;
		else if(top > my_rt.cy - thumb_->GetPosition().Height())
			top = my_rt.cy - thumb_->GetPosition().Height();
		offset = top;
	}


	int new_value = min_value_ + (int)(offset / uni_len);
	new_value += (offset - (new_value - min_value_) * uni_len) > (uni_len / 2) ? 1 : 0;
	SetValue(new_value);
	return true;
}

bool UISlider::DelegteOnThumbEvent(void* tag)
{
	UIEvent *evt = (UIEvent *)tag;
	SS_ASSERT(evt != NULL);

	if(evt->type == kEvtLButtonDown)
	{
		draging_ = true;
		drag_mouse_pt_ = evt->mouse_point;
		drag_thmub_pt_.x = thumb_->GetPresetPosition().GetLeft();
		drag_thmub_pt_.y = thumb_->GetPresetPosition().GetTop();
		SendNotify(
			UINotify(_T("slider_drag_begin"), this, MAKEINT64(0, value_))
			);

	}else if(evt->type == kEvtButtonUp && evt->wparam == WM_LBUTTONUP)
	{
		if(draging_)
		{
			draging_ = false;

			SendNotify(
				UINotify(_T("slider_drag_end"), this, MAKEINT64(0, value_))
				);

			SetNeedUpdate(true);
		}
	}else if(evt->type == kEvtMouseMove)
	{
		if(draging_)
		{
			int tleft = 0, ttop = 0;
			UIPoint pt = evt->mouse_point;
			if(GetThumbLeftTopOnDrag(tleft, ttop, pt))
			{
				UIPresetPosition pp = thumb_->GetPresetPosition();
				if(slider_type_ == kSTypeHorz)
				{
					pp.SetLeft(tleft, ud_convert_ ? false : true);
				}else if(slider_type_ == kSTypeVert)
				{
					pp.SetTop(ttop, ud_convert_ ? false : true);
				}
				thumb_->SetPresetPosition(pp);
			}
		}

	}

	return false;
}

_SSUIL_END
_SSL_END
